﻿package render3d.adapters 
{
	import alternativa.engine3d.containers.KDContainer;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.objects.Mesh;
	import alternativa.engine3d.objects.SkyBox;
	import alternativa.engine3d.objects.Sprite3D;
	import alternativa.engine3d.primitives.Plane;
	import exey.utils.BitmapUtils;
	import flash.display.BitmapData;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import render3d.adapters.abstract.Render3DAdapterAbstract;
	import render3d.CrossEngineObject3D;
	import render3d.interfaces.IRender3DAdapter;
	import render3d.interfaces.IRender3DForObject3D;
	
	/**
	 * Alternativa3D 7.5 Adapter
	 * @author Exey Panteleev
	 */
	public class Alternativa3DAdapter extends Render3DAdapterAbstract implements IRender3DAdapter, IRender3DForObject3D
	{
		private var container:KDContainer;
		private var camera:Camera3D;
		private var view:View;
		
		override public function get GRID_Y_FIX():int { return 0 };
		
		public function Alternativa3DAdapter()
		{
			initScene();
		}
		
		public function initScene():void 
		{
			container = new KDContainer();		
			camera = new Camera3D();
			container.addChild(camera);
			view = new View(800, 600);
			camera.view = view;
			viewContainer.addChild(view);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Camera
		//
		//--------------------------------------------------------------------------		
		
		public function setCameraPosition(x:Number = NaN, y:Number = NaN, z:Number = NaN):void 
		{
			if (!isNaN(x)) camera.x = x;
			if (!isNaN(y)) camera.y = y;
			if (!isNaN(z)) camera.z = z;
		}
		
		public function moveCamera(forwardSpeed:Number, rightSpeed:Number, jumpSpeed:Number):void 
		{
			camera.x += rightSpeed;
			camera.y += forwardSpeed;
			camera.z += jumpSpeed;
		}
		
		public function rotateCamera(x:Number = NaN, y:Number = NaN, z:Number = NaN):void 
		{
			if (!isNaN(x)) camera.rotationX = x*toRADIANS;
			if (!isNaN(y)) camera.rotationY = y*toRADIANS;
			if (!isNaN(z)) camera.rotationZ = z*toRADIANS;
		}
		
		public function lookCamera(mouseX:Number, mouseY:Number):void 
		{
			camera.rotationX -= mouseY * toRADIANS;
			camera.rotationZ -= mouseX * toRADIANS;
		}
		
		public function getCameraTransformation():Matrix3D 
		{
			return camera.matrix.clone();
		}
		
		public function getCameraHeight():Number 
		{
			return camera.z;
		}

		public function getCameraPanAngle():Number 
		{
			return camera.rotationZ;
		}
		
		//--------------------------------------------------------------------------
		//
		//  3D Objects 
		//
		//--------------------------------------------------------------------------
		
		public function createPlane(bitmapData:BitmapData, width:int, height:int, type:String = ""):CrossEngineObject3D
		{
			var plane:Plane = new Plane(width, height, 1, 1);
			plane.setMaterialToAllFaces(new TextureMaterial(bitmapData));
			//plane.sorting = Sorting.NONE;
			//plane.clipping = Clipping.FACE_CULLING;
			var crossEngineObject3D:CrossEngineObject3D = new CrossEngineObject3D(this, plane);
			return crossEngineObject3D;				
		}
				
		public function createSkybox(back:BitmapData, left:BitmapData, front:BitmapData, right:BitmapData, top:BitmapData, bottom:BitmapData):CrossEngineObject3D
		{
			var backMaterial:TextureMaterial = new TextureMaterial(back);
			var leftMaterial:TextureMaterial = new TextureMaterial(left);
			var frontMaterial:TextureMaterial = new TextureMaterial(front);
			var rightMaterial:TextureMaterial = new TextureMaterial(right);
			top = BitmapUtils.rotateRectangular(top, Math.PI);
			var topMaterial:TextureMaterial = new TextureMaterial(top);
			var bottomMaterial:TextureMaterial = new TextureMaterial(bottom);
			
			var skybox:SkyBox = new SkyBox(20000);
			if (back) skybox.getSide(SkyBox.BACK).material = backMaterial;
			if (left) skybox.getSide(SkyBox.LEFT).material = leftMaterial;
			if (front) skybox.getSide(SkyBox.FRONT).material = frontMaterial;
			if (right) skybox.getSide(SkyBox.RIGHT).material = rightMaterial;
			if (top) skybox.getSide(SkyBox.TOP).material = topMaterial;
			if (bottom) skybox.getSide(SkyBox.BOTTOM).material = bottomMaterial;
			
			var crossEngineObject3D:CrossEngineObject3D = new CrossEngineObject3D(this, skybox);
			return crossEngineObject3D;			
		}
		
		public function createSprite3D(bitmapData:BitmapData, type:String = ""):CrossEngineObject3D
		{
			var sprite3D:Sprite3D = new Sprite3D(bitmapData.width, bitmapData.height, new TextureMaterial(bitmapData));
			sprite3D.calculateBounds();
			var crossEngineObject3D:CrossEngineObject3D = new CrossEngineObject3D(this, sprite3D);
			return crossEngineObject3D;				
		}
		
		public function changeTexture( bitmapData:BitmapData, targetObject3D:* ):void 
		{
			if (targetObject3D is Sprite3D)
				Sprite3D(targetObject3D).material = new TextureMaterial(bitmapData);
			else if (targetObject3D is Mesh)
				Mesh(targetObject3D).setMaterialToAllFaces(new TextureMaterial(bitmapData))
		}
		
		//--------------------------------------------------------------------------
		//
		//  Common
		//
		//--------------------------------------------------------------------------	
		
		public function update():void 
		{
			camera.render();
		}
		
		public function resize(stageWidth:int, stageHeight:int):void 
		{
			camera.view.width = stageWidth;
			camera.view.height = stageHeight;
		}
		
		public function copyTransformation(sourceMatrix3D:Matrix3D, targetObject3D:*):void 
		{
			Object3D(targetObject3D).matrix = sourceMatrix3D.clone();
			Object3D(targetObject3D).rotationX+=Math.PI*0.5;
		}
		
		public function copyPosition(sourceMatrix3D:Matrix3D, targetObject3D:*):void
		{
			var components:Vector.<Vector3D> = sourceMatrix3D.decompose();
			Object3D(targetObject3D).x = components[0].x;
			Object3D(targetObject3D).y = components[0].y;
			Object3D(targetObject3D).z = components[0].z;
		}		
		
		//--------------------------------------------------------------------------
		//
		//  INTERFACE render3d.interfaces.abstract.IRender3DAbstract
		//
		//--------------------------------------------------------------------------
		
		public function addChild(child:CrossEngineObject3D):void 
		{
			container.addChild(Object3D(child.object3D));
		}
		
		public function removeChild(child:CrossEngineObject3D):void 
		{
			container.removeChild(Object3D(child.object3D));
		}
	}
}